/*
 *  singlestep.h
 *
 *  Created on: July 16, 2011
 *  Author: Mo
 */

#pragma once

#include "ruletangle.h"
#include "eightlayerim.h"
#include "ruletangle2.h"
#include "rulebase.h"
//#include "imagematrix.h"
#include <string>

/*
NOTE: I need to compress the rules. 'Don't care' needs to be added to the rules.
Also, when making the ruletangle for a step which is not the first step 
(i.e. has a history of previous images and a neighborhood size larger than one)
let's first look at the last part of the rule (transition from phase n-1 to n)
and form the rules. If there exists a conflict then we'll look for the transition
from n-2 to n-1 and only that part of the rule. If we reached the transition from 
phase 0 to phase 1 and there were still conflicts, then we will add the rectangles.
If a part of the neighborhood does not help in resolving the conflicts (i.e. two pixels
with the same neighborhood in n-1 have different states in n, and also have the same
neighborhood in n-2), we can either ignor that part (neighborhood n-2) or compress the 
rules in the end.
*/

/*
NOTE2: The development of 'RuleBase' seems to be stopped here. i.e. we do not use rulebases anymore, and
they probably will be replaced by singlesteps. RuleBase and SingleStep both are collection of instructions
that tell what the value of each pixel in the image should be. RuleBase has a c'tor that takes two
ImageMatrix s. ImageMatrix is a binary matrix and the rules will then be generated taking only one neighborhood
in the pase. SingleStep will have a c'tor that takes bitmaps. Bitmaps are grayscale and can provide information
including the past history, enough for a vector of ruletangles to be created.
*/

/**
 * This class implements a set of rules, each represented as a Ruletangle. An object of this class
 * will have enough information to create the next step of an image in a sequence of images. 
 * The ruletangles in an object of this class will have the neighborhood size equal to the number of 
 * the images in the image sequence minus one. 
 */

class SingleStep
{
private:
	/**
	 * Tells the size of IF part (in neighborhoos units) plus 1.
	 * phaseNum = n => this->rulebase.size = n-1. (??)
	 * Tells which phase in the sequence of image transitions we are. In other words,
	 * this tells which bit (out of 8 bits of a pixel gray-scale level) we are creating.
	 * This also determines the size of rules' neighborhood as well as number of B&W images
	 * in the sequence of input images in nextImage() [?] function.
	 */
	//I do not remember why it is the size of the IF part 'PLUS ONE'. However, I added one to the 
	// int RuleBase::updateFromRuleBase() to be compatible with this. Here it is: this->phaseNum = rb.getNBsperOneLongInstance() + 1;
	int phaseNum;	
	
	/**
	 * Stores the set of ruletangles with which the next phase of the image can be created.
	 */
	vector<Ruletangle2> ruletangle;

	/** Tells the next state of a pixel whose history and coordinate is given.
	 *  \NOTE returns 0 if there is no ruletangle matching the input.
	 */
	int nextState (const vector<Neighborhood*>& nb, const Coordinate& coo) const;

public:



	/**Returns the number of Ruletangles in the object.*/
	int getRuletangleNum () const {return this->ruletangle.size();}

	/** Returns the phase (AKA step) number. The first step where there is no image and we start 
	  * from a blank image is phase 0. Phase N is when the lenght of the IF part or the rules is N.
	  */
	int getPhaseNum() const {return this->phaseNum;}

	/**
	 * Creates the SingleStep according to multiple imagematrices in the given EightLayerIM object. 
	 * The first eim.validImages - 1 images will be used for the IF part and the last one is the THEN
	 * part.
	 */
	SingleStep (const EightLayerIM& eim, Rectangle2FormationAlgorithmType algorithmType = bottomup);

	/**
	 * Constructor. Gets an EightLayer IM who has only "phaseNum" number of valid images and creates an object
	 * whose instances are 'phaseNum-1' x NEIGHBORHOODSIZE long.
	 */
	SingleStep (const EightLayerIM& lImage, int phaseNum, Rectangle2FormationAlgorithmType algorithmType = bottomup);

	/**
	 * Constructor. Creates a SingleStep using the image startI(start Image) to endI(end Image) stored in the 
	 * provided EightLayerIM object.
	 * \note The last image (i.e. endI) is used for the THEN part. The size of IF part (i.e. phaseNum) will be
	 * endI - startI
	 */
	SingleStep (const EightLayerIM& lImage, int startI, int endI, Rectangle2FormationAlgorithmType algorithmType = bottomup);

	/** Constructs the object by reading 'layerNum' number of images from the set of files whose names are given.
	 * imagefile1: baseName_start.bmp, image2: baseName_start+1.bmp, etc.
	 */
	SingleStep (string baseName, int layerNum, string type = "bmp", Rectangle2FormationAlgorithmType algorithmType = bottomup);

	/** 
	 * Updates the data members from the given RuleBase object. This function is almost the trnsformer from
	 * RuleBase to SingleStep.
	 */
	void updateFromRuleBase(const RuleBase& rb, Rectangle2FormationAlgorithmType algorithmType = Rectangle2FormationAlgorithmType::bottomup);

	/**Creates the next phase of the images stored in the source and stores it in the target.
	 */
	void apply (const EightLayerIM& source, ImageMatrix& target) const;
	
	/**Creates the next phase of the images stored in the input EightLayerIM and extends it to include one more valid ImageMatrix.
	 */
	void apply (EightLayerIM& lImage) const;

	/**Creates the next phase of the images stored in the input EightLayerIM by using the layer firstLayer to lastLayer
	 * of the given EightLayerIM. It also extends the EightLayerIM (or update it) to have the new layer lastLayer+1.
	 */
	void apply (EightLayerIM& lImage, int firstLayer, int lastLayer) const;

	/** Predicts and adds the next image layer of an EightLayerIM. Uses the history from the input EightLayerIM
	 * and the rules stored in the caller SingleStep object to create the new layer. The new layer is added to the 
	 * input EightLayerIM as a new layer.
	 */
	void addNextLayer (EightLayerIM& im) const {this->apply(im);}

	///**Creates the next phase of the source ImageMatrix and stores it in the target ImageMatrix.
	// */
	//void apply (const ImageMatrix& source, ImageMatrix& target) const;

	///** Extends the current object to phaseNum+1 by infering new longer rules from the given ImageMatrix.
	// */
	//void addNewPhase (const ImageMatrix& nextPhase);

	void print (void);

	/**
	 * Returnes the net information size (in bits) stored in an object.
	 * The returned value is the minimum number of bits that efficiently can give us all the information
	 * in an object.
	 */
	int getNetInfoSizeInBits(void) const;

	friend ostream& operator<< (ostream& stream, const SingleStep& ss);
};